<?php

namespace Yiru\LaravelComposer\Console\Commands;

use Illuminate\Support\Str;
use Illuminate\Support\Arr;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Auth;
use Log;
use DB;
use Exception;

use Symfony\Component\Console\Input\InputOption;

use Josh\Terminal\TerminalFacade    as Terminal;
//https://github.com/mikehaertl/php-shellcommand
use mikehaertl\shellcommand\Command as Shell;
use Yiru\LaravelComposer\Helpers\Npm;

class NpmInstall extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'npm:install {pkgs}';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'install npm package for laravel';

    private $pacakge;

    public function __construct()
    {
        parent::__construct();        
    }

    /**
     * Execute the console command.
     *
     * @return mixed
     */
    public function handle()
    {
        $pkgs = $this->argument('pkgs')?:null;
        if($pkgs=='all'){
            [$pkgs,$configs] = Arr::divide(config('npm'));
        }else $pkgs = explode(',',$pkgs);
          
        // foreach ($pkgs as $pkg) {
        //     $envName=Npm::envName($pkg);
        //     if(empty(config('npm.pkgs.'.$envName,null))){
        //         throw new Exception('Package '.$pkg.' no config');
        //     }            
        // }        
        $this->require($pkgs);        
    }

    protected function  shell($shell,$msg){
       
        if($shell->execute()){
            $ret=$shell->getOutput();             
            $this->output->success($ret);  
            return $ret;
        }else{
            $ret=$shell->getError();
            $this->output->error($hell.':'.$ret);  
            $exitCode = $shell->getExitCode();
            throw new Exception($msg);
        }    
    }
    /// 本地文件包仓库
    // {
    //     "type": "path",
    //     "url": "../packages/*/*",
    //     "options": {
    //       "symlink": true
    //     }   
    // },   
     /**
     * npm Require package
     *
     * @return bool
     */
    public function repo($pkgs){
       // '--save --save-dev'
    }
    
    /// install to target dir
    protected function deploy($pkg){
        if(empty($pkg)){
            throw new Exception('必须提供包');
        }
        $target_dir=Npm::getEnvDir($pkg);        
        if(!file_exists($target_dir)){
             $shell= new Shell('mkdir -p '.$target_dir);
             $ret=Npm::shell($shell,$this->output,"create directory");
        }
        $npm_dirs=Npm::getDistDir($pkg);
        dump($npm_dirs);        

        foreach ($npm_dirs as $npm_dir) {
            
            dump($npm_dir);
            dump($target_dir);
            $command='';            
            if(Str::endsWith($npm_dir,'dist')){
                $command='cp -rdf  '.$npm_dir.'/* '.$target_dir;
            }else {
                
                $command='cp -rdf  '.$npm_dir.' '.$target_dir;
            }            
            $shell=new Shell($command);    
            $ret=Npm::shell($shell,$this->output,"copy package");
        }
        // $npm_dir=base_path('node_modules/'.$pkg.'/dist/');
        // if(file_exists($npm_dir)){
        //      $shell= new Shell('cp -rdf  '.$npm_dir.'/* '.$target_dir);
        //      $ret=Npm::shell($shell,$this->output,"copy package");
        // }
        return $ret;        
    }

    /**
     * npm install package
     * @return bool
     */
    public function require($pkgs)
    {
        $npmPkgs="";
        $envPkgs=[];
        if(!is_array($pkgs)) $pkgs=[$pkgs];
        foreach ($pkgs as $pkg) {
            $npmPkg=Npm::getPkg($pkg);            
            $npmPkgs= Str::of($npmPkgs)->append(" ".$npmPkg);            
            Arr::set($envPkgs,$npmPkg,Npm::envName($pkg));            
        }
        
        $shell= new Shell('npm install --verbose '.$npmPkgs);
        $shell->setOptions([
            'procEnv' => [
                'PATH'=>"\$PATH:/usr/local/node/bin"
            ]
        ]);
        $ret=Npm::shell($shell,$this->output,"npm install");
        $retPkgs=Str::of($ret)->matchAll('/([\S]*@[\S]*)/')->toArray();
        foreach ($retPkgs as $pkg) {
            $this->deploy($pkg);                        
            $this->env(Arr::get($envPkgs,$pkg),$pkg);
        }
    }

    /**
     * Publish package
     * @return bool
     */
    public function publish($pkgs)
    {
       
    }

    /**
     * migrations package, 
     * Check config/package.{package}.table, if table exist, do nothing 
     * otherwise migration, 
     * @return bool
     */
    public function migrations($pkg)
    {
        
            
            
    }

    /**
     * package, 
     * Check config/package.{package}.table, if table exist, do nothing 
     * otherwise migration, 
     * @return bool
     */
    public function view($pkg)
    {
        
            
            
    }

    /**
     * package, 安装命令
     * Check config/package.{package}.dependency, if table exist, do nothing 
     * otherwise migration, 
     * @return bool
     */
    public function dependency($pkgs)
    {
        
           
    }
   
    /**
     * env配置
     * 配置env的环境变量     
     * @return bool
    */
    public function env($envPkg,$npmPkg)
    {
        $envItems=config('npm.pkgs.'.$envPkg.'.envs');
        $env_url=Npm::getEnvUrl($npmPkg);

        if(!empty($envItems)){            
            foreach ($envItems as $key) {
                $shell=new Shell('php artisan dotenv:set-key '.$key.' '.$env_url.' '.'"for '.$envPkg.'"');
                Npm::shell($shell,$this->output,"env set failed");
            }
        }

        $envItems=config('package.frontend.'.$envPkg.'.envs');
        if(!empty($envItems)){            
            foreach ($envItems as $key => $val ) {                
                $shell=new Shell('php artisan dotenv:set-key '.$key.' '.$env_url.'/'.$val.' '.'"for '.$envPkg.'"');
                dump('php artisan dotenv:set-key '.$key.' '.$env_url.$val.' '.'"for '.$envPkg.'"');
                Npm::shell($shell,$this->output,"env set failed");
            }
        }
        $shell=new Shell('php artisan config:cache');    
        Npm::shell($shell,$this->output,"config:cache failed");
    }
    /**
     * Config  package， 
     * Check config/package.{package}.config, if config item update config/XXX.XXXX
     * @return bool
     */
    public function config($pkgs)
    {
       
    }

    protected function getOptions()
    {
        return [
            ['c', 'c', InputOption::VALUE_OPTIONAL, 'Connection name'],
        ];
    }

}